/**
 * File Created at 2016年6月20日
 * Copyright 2016 汉威.智慧环保事业部 Limited.
 * All rights reserved.
 */
package com.sc.datacollect.util;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * 数据推送
 *
 * @author duqunxing
 */
public class Client {
    private static Logger log = Logger.getLogger(Client.class);
    private HttpClientContext localContext = null;
    private CookieStore cookieStore = null;
    private CloseableHttpClient httpClient = null;

    private Client() {
    }

    private static Client client;

    public static Client getInstance() {
        if (client == null) {
            client = new Client();
        }
        return client;
    }

    /**
     * 提交数据
     *
     * @param params
     * @return
     * @throws Exception
     */
    public String execute(String methodName, Map<String, Object> params, Map<String, Object> pathParams, RequestMethod requestMethod) {
        switch (requestMethod) {
            case GET:
                return get(getUri(methodName, pathParams), getParamsStr(params));
            case POST:
                return post(getUri(methodName, pathParams), getParams(params));
            case PUT:
                return put(getUri(methodName, pathParams), getParams(params));
            case DELET:
                return delete(getUri(methodName, pathParams), getParamsStr(params));
            default:
                break;
        }
        return null;
    }


    private void setCookieStore(HttpResponse response) {
        this.cookieStore = new BasicCookieStore();
        Header header = response.getFirstHeader("Set-Cookie");
        if (null != header) {
            String setCookie = response.getFirstHeader("Set-Cookie").getValue();
            String jSessionId = setCookie.substring("JSESSIONID=".length(), setCookie.indexOf(";"));
            log.info("JSESSIONID:" + jSessionId);

            BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", jSessionId);
            cookie.setVersion(0);
            cookie.setDomain(ClientConfig.getInstance().getHost());
            cookie.setPath("/");

            this.cookieStore.addCookie(cookie);
        }
    }

    private void setLocalContext() {
        this.localContext = HttpClientContext.create();
        this.localContext.setCookieStore(this.cookieStore);
    }

    private CloseableHttpClient getHttpClient() {
        if (httpClient == null) {
            this.httpClient = HttpClients.createDefault();
        }
        return this.httpClient;
    }

    private String get(String uri, String paramsPairs) {
        CloseableHttpResponse response = null;
        try {
            if (null != paramsPairs && !paramsPairs.isEmpty()) {
                uri = uri.contains("?") ? uri + "&" + paramsPairs : uri + "?" + paramsPairs;
            }
            HttpGet get = new HttpGet(uri.trim().replace(" ", "%20"));
            get.setHeaders(getHeader());
            response = getHttpClient().execute(get, localContext);

            int status = response.getStatusLine().getStatusCode();
            if (status >= 200 && status < 300) {

                HttpEntity responseEntity = response.getEntity();
                String result = EntityUtils.toString(responseEntity);
                return result;
            } else {
                get.abort();
                log.info("Unexpected response status: " + status);
            }
        } catch (Exception e) {
            log.error(e);
        }
        return null;
    }

    private String post(String uri, List<BasicNameValuePair> paramsPairs) {
        CloseableHttpResponse response = null;
        try {
            HttpPost post = new HttpPost(uri.trim().replace(" ", "%20"));
            post.setHeaders(getHeader());
            HttpEntity requestEntity = new UrlEncodedFormEntity(paramsPairs, "UTF-8");
            post.setEntity(requestEntity);
            response = getHttpClient().execute(post, localContext);


            int status = response.getStatusLine().getStatusCode();
            if (status >= 200 && status < 300) {
                int endIndex = uri.lastIndexOf("?");
                int startIndex = uri.lastIndexOf("/", endIndex);
                String reqUri = uri.substring(startIndex, endIndex);
                if ("authen".equals(reqUri)) {
                    setCookieStore(response);
                    setLocalContext();

                }
                if ("logout".equals(reqUri)) {
                    this.cookieStore = null;
                    this.localContext = null;
                }

                HttpEntity responseEntity = response.getEntity();
                String result = EntityUtils.toString(responseEntity);
                return result;
            } else {
                post.abort();
                log.info("Unexpected response status: " + status);
            }
        } catch (Exception e) {
            log.error(e);
        }
        return null;
    }

    private String put(String uri, List<BasicNameValuePair> paramsPairs) {
        CloseableHttpResponse response = null;
        try {
            HttpPut put = new HttpPut(uri.trim().replace(" ", "%20"));
            put.setHeaders(getHeader());
            HttpEntity requestEntity = new UrlEncodedFormEntity(paramsPairs, "UTF-8");
            put.setEntity(requestEntity);
            response = getHttpClient().execute(put, localContext);


            int status = response.getStatusLine().getStatusCode();
            if (status >= 200 && status < 300) {

                HttpEntity responseEntity = response.getEntity();
                String result = EntityUtils.toString(responseEntity);
                return result;
            } else {
                put.abort();
                log.info("Unexpected response status: " + status);
            }
        } catch (Exception e) {
            log.error(e);
        }
        return null;
    }

    private String delete(String uri, String paramsPairs) {
        CloseableHttpResponse response = null;
        try {
            if (null != paramsPairs && !paramsPairs.isEmpty()) {
                uri = uri.contains("?") ? uri + "&" + paramsPairs : uri + "?" + paramsPairs;
            }
            HttpDelete delete = new HttpDelete(uri.trim().replace(" ", "%20"));
            delete.setHeaders(getHeader());
            response = getHttpClient().execute(delete, localContext);
            int status = response.getStatusLine().getStatusCode();
            if (status >= 200 && status < 300) {

                HttpEntity responseEntity = response.getEntity();
                String result = EntityUtils.toString(responseEntity);
                return result;
            } else {
                delete.abort();
                log.info("Unexpected response status: " + status);
            }
        } catch (Exception e) {
            log.error(e);
        }
        return null;
    }


    private String getUri(String methodName, Map<String, Object> pathParams) {
        //封装路径
        ClientConfig clientConfig = ClientConfig.getInstance();
        String uri = clientConfig.getUri(methodName);
        if (null != pathParams && !pathParams.isEmpty()) {
            Iterator<String> pathParamsIter = pathParams.keySet().iterator();
            while (pathParamsIter.hasNext()) {
                String name = pathParamsIter.next();
                String value = (String) pathParams.get(name);
                uri = uri.replace("{" + name + "}", value);
            }
        }
        String baseUri = clientConfig.getSchema() + "://" + clientConfig.getHost() + ":" + clientConfig.getPort() + "/";
        return baseUri + uri;
    }

    private List<BasicNameValuePair> getParams(Map<String, Object> params) {
        //封装参数
        List<BasicNameValuePair> paramsPairs = new ArrayList<>();
        if (null != params && !params.isEmpty()) {
            Iterator<String> paramsIter = params.keySet().iterator();
            while (paramsIter.hasNext()) {
                String name = paramsIter.next();
                String value = (String) params.get(name);
                paramsPairs.add(new BasicNameValuePair(name, value));
            }
            return paramsPairs;
        }
        return paramsPairs;
    }

    private String getParamsStr(Map<String, Object> params) {
        //封装参数
        String paramsStr = "";
        if (null == params || params.isEmpty()) {
            return null;
        }
        Iterator<String> paramsIter = params.keySet().iterator();
        while (paramsIter.hasNext()) {
            String name = paramsIter.next();
            String value = (String) params.get(name);
            paramsStr += name + "=" + value + "&";
        }
        return (null != paramsStr && !paramsStr.isEmpty()) ? paramsStr.substring(0, paramsStr.length() - 1) : "";
    }


    private Header[] getHeader() {
        Header[] headers = new Header[2];
        headers[0] = new BasicHeader(HttpHeaders.ACCEPT, "application/json");
        headers[1] = new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
        return headers;
    }
}
